﻿//
// Created by Xinjian Chen on 3/20/23.
//

#ifndef MIDDLEWARE_DDSBRIDGE_H
#define MIDDLEWARE_DDSBRIDGE_H

#include <cstdint>

/******************************************************************************************
 * we support the following data type for transmission, please add the following FooMsg struct
 * in an idl file and compile it to generate files which define FooMsg, FooMsgSeq,
 * FooMsgTypeSupport, FooMsgDataWriter and FooMsgDataReader, etc..
typedef sequence<octet> OctetSeq;
struct FooMsg{
    long length;
    OctetSeq data;
};
*******************************************************************************************/

struct ZY_Duration_t {
    long sec;
    unsigned long nanosec;
};

typedef long ZY_DomainId_t;
typedef long ZY_ReturnCode_t;
const ZY_ReturnCode_t ZY_RETCODE_OK = 0;
const ZY_ReturnCode_t ZY_RETCODE_ERROR = 1;
const ZY_ReturnCode_t ZY_RETCODE_UNSUPPORTED = 2;
const ZY_ReturnCode_t ZY_RETCODE_BAD_PARAMETER = 3;
const ZY_ReturnCode_t ZY_RETCODE_PRECONDITION_NOT_MET = 4;
const ZY_ReturnCode_t ZY_RETCODE_OUT_OF_RESOURCES = 5;
const ZY_ReturnCode_t ZY_RETCODE_NOT_ENABLED = 6;
const ZY_ReturnCode_t ZY_RETCODE_IMMUTABLE_POLICY = 7;
const ZY_ReturnCode_t ZY_RETCODE_INCONSISTENT_POLICY = 8;
const ZY_ReturnCode_t ZY_RETCODE_ALREADY_DELETED = 9;
const ZY_ReturnCode_t ZY_RETCODE_TIMEOUT = 10;
const ZY_ReturnCode_t ZY_RETCODE_NO_DATA = 11;
const ZY_ReturnCode_t ZY_RETCODE_ILLEGAL_OPERATION = 12;

/* a strategy for opaque pointer, since we can not use template here.
 * please reinterpret_cast from opaque pointer to specific pointer or
 * specific pointer to opaque pointer if necessary.
 **/
struct ZY_DomainParticipantFactory;
struct ZY_DomainParticipant;
struct ZY_Publisher;
struct ZY_Subscriber;
struct ZY_Topic;
struct ZY_DataWriter;
struct ZY_DataReader;

// we are only interested in how many readers have been matched.
extern void DataWriterListener_on_publication_matched(ZY_DataWriter *the_writer, int match_count);

extern void DataReaderListener_on_data_available(ZY_DataReader *the_reader);

class DDSBridge {
public:
    virtual ~DDSBridge();

    /* 添加环境变量和启动参数，初始化DomainParticipantFactory，设置监听等 */
    virtual ZY_DomainParticipantFactory *initDomainParticipantFactory() = 0;

    /* 创建DomainParticipant，设置Qos策略，暂不需要Listener */
    virtual ZY_DomainParticipant *createParticipant(ZY_DomainParticipantFactory *factory, ZY_DomainId_t domainId) = 0;

    /* 销毁Participant实例 */
    virtual ZY_ReturnCode_t
    deleteParticipant(ZY_DomainParticipantFactory *factory, ZY_DomainParticipant *participant) = 0;

    /* 创建Publisher，设置Qos策略，暂不需要Listener */
    virtual ZY_Publisher *createPublisher(ZY_DomainParticipant *participant) = 0;

    /* 销毁Publisher实例 */
    virtual ZY_ReturnCode_t deletePublisher(ZY_DomainParticipant *participant, ZY_Publisher *publisher) = 0;

    /* 创建Subscriber，设置Qos策略，暂不需要Listener */
    virtual ZY_Subscriber *createSubscriber(ZY_DomainParticipant *participant) = 0;

    /* 销毁Subscriber实例 */
    virtual ZY_ReturnCode_t deleteSubscriber(ZY_DomainParticipant *participant, ZY_Subscriber *subscriber) = 0;

    /* 由编译idl后生成的FooTypeSupport来注册数据类型，如果type_name已定义，可以忽略type_name参数 */
    virtual ZY_ReturnCode_t registerDataType(ZY_DomainParticipant *participant, const char *type_name) = 0;

    /* 创建Topic实例，设置Qos策略，暂不需要Listener */
    virtual ZY_Topic *createTopic(ZY_DomainParticipant *participant, const char *topic_name, const char *type_name) = 0;

    /* 销毁Topic实例 */
    virtual ZY_ReturnCode_t deleteTopic(ZY_DomainParticipant *participant, ZY_Topic *topic) = 0;

    /* 根据Topic实例创建DataWriter，设置Qos策略
     * 必须添加listener, 并在on_publication_matched事件中调用DataWriterListener_on_publication_matched方法 */
    virtual ZY_DataWriter *createDataWriter(ZY_Publisher *publisher, ZY_Topic *topic) = 0;

    /* 成功创建DataWriter后调用
     * 如果DataWriter不是自动使能，在此处使能 */
    virtual ZY_ReturnCode_t enableDataWriter(ZY_DataWriter *dataWriter) = 0;

    /* 销毁DataWriter实例 */
    virtual ZY_ReturnCode_t deleteDataWriter(ZY_Publisher *publisher, ZY_DataWriter *writer) = 0;

    /* 根据Topic实例创建DataReader，设置Qos策略
     * 必须添加listener, 并在on_data_available事件中调用DataReaderListener_on_data_available方法 */
    virtual ZY_DataReader *createDataReader(ZY_Subscriber *subscriber, ZY_Topic *topic) = 0;

    /* 成功创建DataReader后调用
     * 如果DataReader不是自动使能，在此处使能 */
    virtual ZY_ReturnCode_t enableDataReader(ZY_DataReader *dataReader) = 0;

    /* 销毁DataReader实例 */
    virtual ZY_ReturnCode_t deleteDataReader(ZY_Subscriber *subscriber, ZY_DataReader *reader) = 0;

    /* 这是一个回调方法，先根据给定buffer和数据长度填充Foo结构，然后调用FooDataWriter的write方法 */
    virtual ZY_ReturnCode_t onSendData(ZY_DataWriter *writer, const char *buffer, int64_t length) = 0;

    /* 如果Qos策略是RELIABLE，必须阻塞等待直到time out，否则立即返回 ZY_RETCODE_OK */
    virtual ZY_ReturnCode_t wait_for_acknowledgments(ZY_DataWriter *writer, ZY_Duration_t timeout) = 0;

    /* 这是一个回调方法，获取一个Sample，拷贝数据到指定buffer，并返回实际数据长度，可按以下步骤实现
     * 1. 分配FooSeq, SampleInfoSeq，result = -1
     * 2. 调用FooDataReader的take方法(参数max_samples必须为1)
     * 3. 如果返回值不是 ZY_RETCODE_OK，直接返回-1
     * 4. 遍历SampleInfoSeq，找到一个valid_data字段为true的SampleInfo，并解析FooSeq对应的Foo
     * 5. 如果Foo.length > maxLength，拷贝maxLength长度的数据到指定buffer，这时数据会被截取，流图设计要尽量避免此类情况
     * 6. 如果Foo.length属于区间(0 maxLength]，则拷贝Foo.data到指定的buffer
     * 7. 设置result为buffer接收的实际数据长度
     * 8. 如果未找到有效的SampleInfo，设置result为-1
     * 9. 调用FooDataReader的return_loan方法(不是必须，应根据实际情况调整)，并返回result
     * */
    virtual int64_t onTakeOneSample(ZY_DataReader *reader, char *buffer, int64_t maxLength) = 0;
};


#endif //MIDDLEWARE_DDSBRIDGE_H
